class SuperTable {
    /* 构造器 */
    constructor(arr = []) {
        // 接收并保存数据
        this.arr = arr;
        this.initOK = false;

        if (this.arr.length > 0) {
            this.init();
        }
    }

    /* 添加数据接口 */
    insertData(obj) {
        this.arr.push(obj);
        if (!this.initOK) {
            this.init(this.arr);
        } else {
            console.log("追加数据", obj);
            this.addData(obj, {
                inputDisabled: true,
                useTrWrapper: true,
                btnEditText: "编辑",
            });
        }
    }

    /* 初始化 */
    init(arr) {
        // 保存数据列[name,age,gender,hobby]
        this.dataKeys = Object.keys(this.arr[0]);

        /* 在页面上添加一个table */
        this.table = document.createElement("table");
        this.table.border = "1";
        document.body.appendChild(this.table);

        // 创建表头并完成初次渲染
        this.tableHeadStr = this.createTableHead();
        this.renderData(arr);

        // 找出元素
        this.btnAdd = this.table.querySelector("#btnAdd");

        // 绑定监听器（与用户交互）
        this.bindEventListeners();

        // 标记组件已经完成了初始化
        this.initOK = true;
    }

    /* 删除第index条数据 */
    deleteData(index, e) {
        // 删除数据
        this.arr.splice(index, 1);

        // 重新渲染(性能不OK)
        // this.renderData()

        // 找到第index个tr令其自裁
        // this.table.children[0].children[index + 1].remove()//性能更佳
        this.table.querySelectorAll("tr")[index + 1].remove();

        /* 更新各行的index */
        const trs = Array.from(this.table.querySelectorAll("tr")).slice(1);
        trs.forEach((tr, idx) => {
            tr.querySelectorAll("button").forEach((btn) =>
                btn.setAttribute("index", idx)
            );
        });
    }

    /* 编辑第index条数据 */
    editData(index, e) {
        // 当前行的所有input
        const ips = e.target.parentNode.parentNode.querySelectorAll("input");
        console.log("编辑", index, e);

        if (e.target.innerText === "编辑") {
            e.target.innerText = "确定";

            // 激活第index行的input
            ips.forEach((ip) => ip.removeAttribute("disabled"));
            ips[0].focus();
        } else {
            e.target.innerText = "编辑";

            // 更新数据
            const item = this.arr[index];
            ips.forEach((ip) => {
                // 拿出input框中暗藏的key
                const key = ip.getAttribute("key");
                const value = ip.value;

                // 更新当前数据项
                console.log("提交编辑", index, this.arr);
                item[key] = value;

                // 为当前input添加disabled属性
                ip.setAttribute("disabled", true);
            });
        }
    }

    /* 生成一个所有key均为默认值的“空白”数据 */
    createDefaultData() {
        /* 构建一个空对象 */
        const copy = {};

        // 参考模板设置key-value，所有value使用""作为默认值
        for (let key of this.dataKeys) {
            copy[key] = "";
        }

        // 返回空白数据
        console.log("copy=", copy);
        return copy;
    }

    /*  */
    addData(data, options) {
        // 生成默认行tr的html字符串
        const trStr = this.createTrStr(
            // 生成默认空白数据
            data,

            // 插入到arr的末尾
            this.arr.length - 1,

            // 配置：input不要打开disabled 不要最外层的tr包裹
            // {
            //     inputDisabled: false,
            //     useTrWrapper: false,
            //     btnEditText: "确定",
            // }
            options
        );

        /* 创建tr元素并设置innerHTML */
        const tr = document.createElement("tr");
        // tr.innerHTML = trStr.replace(/((<tr>)|(<\/tr>))/g, "")
        tr.innerHTML = trStr;

        // 将新生成的tr插入到tbody【新增按钮】所在行的前面
        // this.table.children[0]即tbody
        this.table.children[0].insertBefore(
            // 要插入的元素
            tr,
            // 插在谁之前（btnAdd所在的td所在的tr）
            this.btnAdd.parentNode.parentNode
        );

        // 新增行中的第一列td中的input默认获得焦点
        !options.inputDisabled && tr.children[0].children[0].focus();
    }

    /* 绑定监听器 */
    bindEventListeners() {
        console.log("bindEventListeners", this);

        // 增加数据
        this.btnAdd.onclick = (e) => {
            // 得到一条空白数据
            const emptyData = this.createDefaultData();
            this.arr.push(emptyData);

            this.addData(emptyData, {
                inputDisabled: false,
                useTrWrapper: false,
                btnEditText: "确定",
            });
        };

        // 将【删除】【编辑】按钮的事件委托给table
        this.table.onclick = (e) => {
            /* 点击删除按钮 */
            if (e.target.classList.contains("btnDel")) {
                const index = e.target.getAttribute("index") * 1;
                console.log("删除", index);

                // 删除第index条数据
                this.deleteData(index, e);
            }

            /* 点击编辑按钮 */
            if (e.target.classList.contains("btnEdit")) {
                const index = e.target.getAttribute("index") * 1;

                // 编辑当前行
                this.editData(index, e);
            }
        };
    }

    /* 生成表头 */
    createTableHead() {
        // 制作表头
        let headStr = "<tr>";
        // 拼接若干个th（根据arr中的随便某条数据中的key）
        for (let key in this.arr[0]) {
            headStr += `<th>${key}</th>`;
        }
        // 在tr中拼接操作列 <th>操作</th>
        headStr += "<th>操作</th>";
        headStr += "</tr>";

        return headStr;
    }

    /* 根据数据项生成tr字符串 */
    /**
     * item 数据项
     * index 插入到原始数据的位置（通常是采用arr.push）
     * option.inputDisabled 新生成的tr中的input是否开启【disabled】 默认开启
     * option.useTrWrapper 生成的tr字符串中是否有最外层的<tr>和</tr>
     */
    createTrStr(
        item,
        index,
        option = {
            inputDisabled: true,
            useTrWrapper: true,
            btnEditText: "编辑",
        }
    ) {
        // 根据配置判断是否应该使用tr标签进行包裹
        let trStr = option.useTrWrapper ? "<tr>" : "";

        /* 根据obj的属性值生成td */
        for (let key in item) {
            // 根据用户配置判断是否应该对input使用disabled
            trStr += `<td><input ${
                option.inputDisabled ? "disabled" : ""
            } key=${key} value=${item[key]}></td>`;
        }
        // 丢【删除】【编辑】两个按钮到一个td中
        trStr += `<td>
                    <button class='btnDel' index='${index}'>删除</button>
                    <button class='btnEdit' index='${index}'>${option.btnEditText}</button>
                </td>`;

        // 根据配置判断是否应该使用tr标签进行包裹
        trStr += option.useTrWrapper ? "</tr>" : "";
        return trStr;
    }

    /* 渲染数据 */
    renderData() {
        /* 用一个table显示arr */
        let tableHtml = "";

        //生成表头
        tableHtml += this.tableHeadStr;

        /* 渲染数据 */
        this.arr.forEach((item, index) => {
            tableHtml += this.createTrStr(item, index);
        });

        /* 渲染增加按钮 */
        tableHtml += `
        <tr>
            <td colspan='5' border='0'>
                <button id='btnAdd'>+</button>
            </td>
        </tr>`;

        // 将tableHtmlStr设置为table的innerHTML
        this.table.innerHTML = tableHtml;
    }

    /* 导出数据 */
    exportData() {
        return JSON.stringify(this.arr).replace("\\", "");
    }
}
